/*
Copyright 2024 New Vector Ltd.
Copyright 2017 Aram Sargsyan

SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
 */

#import "MXKAttachmentInteractionController.h"
#import "MXLog.h"

@interface MXKAttachmentInteractionController ()

@property (nonatomic, weak) UIViewController <MXKDestinationAttachmentAnimatorDelegate> *destinationViewController;
@property (nonatomic, weak) UIViewController <MXKSourceAttachmentAnimatorDelegate> *sourceViewController;

@property (nonatomic) UIImageView *transitioningImageView;
@property (nonatomic, weak) id <UIViewControllerContextTransitioning> transitionContext;

@property (nonatomic) CGPoint translation;
@property (nonatomic) CGPoint delta;

@end

@implementation MXKAttachmentInteractionController

#pragma mark - Lifecycle

- (instancetype)initWithDestinationViewController:(UIViewController <MXKDestinationAttachmentAnimatorDelegate> *)viewController sourceViewController:(UIViewController <MXKSourceAttachmentAnimatorDelegate> *)sourceViewController
{
    self = [super init];
    if (self) {
        self.destinationViewController = viewController;
        self.sourceViewController = sourceViewController;
        self.interactionInProgress = NO;
        
        [self preparePanGestureRecognizerInView:viewController.view];
    }
    return self;
}

#pragma mark - Gesture recognizer

- (void)preparePanGestureRecognizerInView:(UIView *)view
{
    UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
    recognizer.minimumNumberOfTouches = 1;
    recognizer.maximumNumberOfTouches = 3;
    [view addGestureRecognizer:recognizer];
}

- (void)handleGesture:(UIPanGestureRecognizer *)recognizer
{
    CGPoint translation = [recognizer translationInView:self.destinationViewController.view];
    self.delta = CGPointMake(translation.x - self.translation.x, translation.y - self.translation.y);
    self.translation = translation;
    
    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:
            
            self.interactionInProgress = YES;
            
            if (self.destinationViewController.navigationController) {
                [self.destinationViewController.navigationController popViewControllerAnimated:YES];
            } else {
                [self.destinationViewController dismissViewControllerAnimated:YES completion:nil];
            }
            
            break;
            
        case UIGestureRecognizerStateChanged:
            
            [self updateInteractiveTransition:(ABS(translation.y) / (CGRectGetHeight(self.destinationViewController.view.frame) / 2))];
            
            break;
            
        case UIGestureRecognizerStateCancelled:
            
            self.interactionInProgress = NO;
            [self cancelInteractiveTransition];
            
            break;
            
        case UIGestureRecognizerStateEnded:
            
            self.interactionInProgress = NO;
            if (ABS(self.translation.y) < CGRectGetHeight(self.destinationViewController.view.frame)/6) {
                [self cancelInteractiveTransition];
            } else {
                [self finishInteractiveTransition];
            }
            
            break;
            
        default:
            MXLogDebug(@"UIGestureRecognizerState not handled");
            break;
    }
}

#pragma mark - UIPercentDrivenInteractiveTransition

- (void)startInteractiveTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
    self.transitionContext = transitionContext;

    [self.destinationViewController prepareSubviewsForTransition:YES];

    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIImageView *destinationImageView = [self.destinationViewController finalImageView];
    destinationImageView.hidden = YES;

    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];
    [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
    UIImageView *originalImageView = [self.sourceViewController originalImageView];
    originalImageView.hidden = YES;
    
    self.transitioningImageView = [[UIImageView alloc] initWithImage:destinationImageView.image];
    self.transitioningImageView.frame = [MXKAttachmentAnimator aspectFitImage:destinationImageView.image inFrame:destinationImageView.frame];
    [[transitionContext containerView] addSubview:self.transitioningImageView];
}

- (void)updateInteractiveTransition:(CGFloat)percentComplete {
    self.destinationViewController.view.alpha = MAX(0, (1 - percentComplete));
    
    CGRect newFrame = CGRectMake(self.transitioningImageView.frame.origin.x, self.transitioningImageView.frame.origin.y + self.delta.y, CGRectGetWidth(self.transitioningImageView.frame), CGRectGetHeight(self.transitioningImageView.frame));
    self.transitioningImageView.frame = newFrame;
}

- (void)cancelInteractiveTransition {
    UIViewController *fromViewController = [self.transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIImageView *destinationImageView = [self.destinationViewController finalImageView];
    UIImageView *originalImageView = [self.sourceViewController originalImageView];

    __weak typeof(self) weakSelf = self;

    [UIView animateWithDuration:([self transitionDuration:self.transitionContext]/2) animations:^{
        if (weakSelf)
        {
            typeof(self) self = weakSelf;
            fromViewController.view.alpha = 1;
            self.transitioningImageView.frame = [MXKAttachmentAnimator aspectFitImage:destinationImageView.image inFrame:destinationImageView.frame];
        }
    } completion:^(BOOL finished) {
        if (weakSelf)
        {
            typeof(self) self = weakSelf;
            destinationImageView.hidden = NO;
            originalImageView.hidden = NO;
            [self.transitioningImageView removeFromSuperview];

            [self.transitionContext cancelInteractiveTransition];
            [self.transitionContext completeTransition:NO];

            [self.destinationViewController prepareSubviewsForTransition:NO];
        }
    }];
}

- (void)finishInteractiveTransition
{
    UIViewController *fromViewController = [self.transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIImageView *destinationImageView = [self.destinationViewController finalImageView];
    
    UIImageView *originalImageView = [self.sourceViewController originalImageView];
    CGRect originalImageViewFrame = [self.sourceViewController convertedFrameForOriginalImageView];

    __weak typeof(self) weakSelf = self;
    
    [UIView animateWithDuration:[self transitionDuration:self.transitionContext] animations:^{
        if (weakSelf)
        {
            typeof(self) self = weakSelf;
            fromViewController.view.alpha = 0.0;
            self.transitioningImageView.frame = originalImageViewFrame;
        }
    } completion:^(BOOL finished) {
        if (weakSelf)
        {
            typeof(self) self = weakSelf;
            [self.transitioningImageView removeFromSuperview];
            destinationImageView.hidden = NO;
            originalImageView.hidden = NO;

            [self.transitionContext finishInteractiveTransition];
            [self.transitionContext completeTransition:YES];
        }
    }];
}

#pragma mark - UIViewControllerAnimatedTransitioning

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return 0.3;
}


@end
